extern crate chrono;
extern crate prettytable;

use chrono::prelude::*;
use prettytable::Table;
use prettytable::row::Row;
use prettytable::cell::Cell;
use prettytable::format;
use prettytable::format::Alignment;

use std::env;
use std::fs;
use std::time::{SystemTime, UNIX_EPOCH};

fn system_time_to_date_time(system_time: SystemTime) -> DateTime<Utc> {
    let (secs, nsec) = match system_time.duration_since(UNIX_EPOCH) {
        Ok(n) => (n.as_secs() as i64, n.subsec_nanos()),
        Err(e) => {
            let dur = e.duration();
            let (sec, nsec) = (dur.as_secs() as i64, dur.subsec_nanos());
            if nsec == 0 {
                (-sec, 0)
            } else {
                (-sec - 1, 1_000_000_000 - nsec)
            }
        }
    };
    Utc.timestamp(secs, nsec)
}

fn main() -> std::io::Result<()> {
    let args = env::args();
    let mut str_directory = String::from(".");
    if args.len() == 2 {
        str_directory = args.last().unwrap();
    } else if args.len() > 2 {
        usage();
        return Ok(());
    }

    let mut table = Table::new();
    table.set_format(*format::consts::FORMAT_CLEAN);
    for entry in fs::read_dir(str_directory)? {
        if let Ok(entry) = entry {
            let path_buf = entry.path();
            let file_name = path_buf.file_name().unwrap();
            let metadata = fs::metadata(&path_buf)?;

            let name = file_name.to_str().unwrap();
            let date_time = system_time_to_date_time(metadata.modified()?);
            let str_time = date_time.format("%Y-%m-%d %H:%M:%S").to_string();
            if path_buf.is_dir() {
                table.add_row(Row::new(vec![
                    Cell::new(str_time.as_str()),
                    Cell::new(" <DIR> "),
                    Cell::new(""),
                    Cell::new(name)
                ]));
            } else {
                let size = metadata.len().to_string();
                let mut cell_size = Cell::new(size.as_str());
                cell_size.align(Alignment::RIGHT);
                table.add_row(Row::new(vec![
                    Cell::new(str_time.as_str()),
                    Cell::new(""),
                    cell_size,
                    Cell::new(name)
                ]));
            }
        }
    }
    table.printstd();
    Ok(())
}

fn usage() {
    println!("rls <dir>")
}
